 
 
 
  
  Fruit教程翻译: 2. 简单系统, 2. Simple system
这是教程的第二部分, 我们会实现一个简单的命令行工具, 它读入一个数字, 将该数字加1,然后输出结果。 在实际的系统中,如此简单的功能 ,一般会写在单个类中 (甚至直接 写在 main() 函数中 ) 。 而在此教程中, 我们 (过度)使用依赖注入技术 , 来将各个功能进行 尽可能细致 地划分, 以向妳展示, Fruit能够帮助 妳利用多个组件构建 出一个复杂系统,同时限制各个组件之间 的依赖关系。
在下面的示例代码中,我们省略掉了那些不相关的代码 (例如,include保护代码 ,以及系统头文件的 include代码) 。完整 的源代码在这里: examples/simple_injection 。
首先,编写一个接口,表示数字加1:
   
    // incrementer.h
   
   
    
    
   
   
    class Incrementer {
   
   
    
   
   
    public:
   
   
    
   
   
      // 返回x + 1
   
   
    。
   
   
    
   
   
      virtual int increment(int x) = 0;
   
   
    
   
   
    };
   
  
数字加1,其实是加法的一个特例,因此,让我们也编写一个接口,表示加法:
   
    // adder.h
   
   
    
    
   
   
    class Adder {
   
   
    
   
   
    public:
   
   
    
   
   
      // 返回
   
   
    x
   
   
    与
   
   
    y
   
   
    的和。
   
   
    
   
   
      virtual int add(int x, int y) = 0;
   
   
    
   
   
    };
   
  
现在,我们想要这样一个组件,当向它提供一个Adder 实现的时候,它会提供一个Incrementer 实现。
   
    // incrementer_impl.h
   
   
    
    
   
   
    #include "incrementer.h"
   
   
    
   
   
    #include "adder.h"
   
   
    
    
   
   
    fruit::Component<fruit::Required<Adder>, Incrementer> getIncrementerImplComponent();
   
  
   
    // incrementer_impl.cpp
   
   
    
    
   
   
    #include "incrementer_impl.h"
   
   
    
    
   
   
    class IncrementerImpl : public Incrementer {
   
   
    
   
   
    private:
   
   
    
   
   
      Adder* adder;
   
   
    
   
   
    
   
   
    
   
   
    public:
   
   
    
   
   
      INJECT(IncrementerImpl(Adder* adder))
   
   
    
   
   
        : adder(adder) {
   
   
    
   
   
      }
   
   
    
   
   
    
   
   
    
   
   
      virtual int increment(int x) override {
   
   
    
   
   
        return adder->add(x, 1);
   
   
    
   
   
      }
   
   
    
   
   
    };
   
   
    
    
   
   
    fruit::Component<fruit::Required<Adder>, Incrementer> getIncrementerImplComponent() {
   
   
    
   
   
      return fruit::createComponent()
   
   
    
   
   
        .bind<Incrementer, IncrementerImpl>();
   
   
    
   
   
    }
   
  
这是我们第一次面对那种本身 有要求的组件。 Fruit组件 是可以有类型要求的, 这些类型,以 fruit::Required<T1, ..., Tn> 的形式在该组件的第一个类型参数中指定。如果 getIncrementerImplComponent() 的原型中未指定要求,那么, Fruit 会寻找针对Adder 的绑定,并且 ,由于未能找到而终止编译 ,报告错误。对于每个组件 ,它尚未绑定的所有必需的类型,都必须被暴露。
注意 , 头文件中暴露的唯一信息就是, 该模块要求什么、提供什么。 IncrementerImpl 类,只在 .cpp文件 中定义。 这与 透明指针 类似。
注意:习惯了C++风格的读者,可能希望用一个匿名的命名空间来将这个类包装起来。这是一个合理的预期,因为这个类仅仅在该.cpp文件中使用。出于易读性考虑,我们省略掉了这个匿名的命名空间。
同时,这里也缺少了虚析构函数,这也是有意为之,因为,Fruit会在注入器中处理各个对象的析构过程,它会自动销毁那些实体(concrete)类(不是利用指向基类的指针来实现的)。即使妳打开了"-W -Wall"选项,编译器也不会报告警告。
现在,让我们来实现Adder。
   
    // simple_adder.h
   
   
    
    
   
   
    #include "adder.h"
   
   
    
    
   
   
    fruit::Component<Adder> getSimpleAdderComponent();
   
  
   
    // simple_adder.cpp
   
   
    
   
   
    
   
   
    #include "simple_adder.h"
   
   
    
    
   
   
    class SimpleAdder : public Adder {
   
   
    
   
   
    public:
   
   
    
   
   
      INJECT(SimpleAdder()) = default;
   
   
    
   
   
    
   
   
    
   
   
      virtual int add(int x, int y) override {
   
   
    
   
   
        return x + y;
   
   
    
   
   
      }
   
   
    
   
   
    };
   
   
    
    
   
   
    fruit::Component<Adder> getSimpleAdderComponent() {
   
   
    
   
   
      return fruit::createComponent()
   
   
    
   
   
        .bind<Adder, SimpleAdder>();
   
   
    
   
   
    }
   
  
这个组件狠简单,它的代码已经自解释了。
现在, 我们拥有了一个能够提供 Adder 的组件, 以及一个需要 Adder 而又提供了 Incrementer 的组件。 ,现在,我们要将这两个组件复合起来。
   
    // simple_incrementer.h
   
   
    
    
   
   
    #include "incrementer.h"
   
   
    
    
   
   
    fruit::Component<Incrementer> getSimpleIncrementerComponent();
   
  
   
    // simple_incrementer.cpp
   
   
    
    
   
   
    #include "simple_incrementer.h"
   
   
    
    
   
   
    #include "incrementer_impl.h"
   
   
    
   
   
    #include "simple_adder.h"
   
   
    
    
   
   
    fruit::Component<Incrementer> getSimpleIncrementerComponent() {
   
   
    
   
   
      return fruit::createComponent()
   
   
    
   
   
        .install(getIncrementerImplComponent())
   
   
    
   
   
        .install(getSimpleAdderComponent());
   
   
    
   
   
    }
   
  
install() 是一个操作函数,它将 一个子组件“安装”到当前组件中去。 我们在上一页教程中已经观摩过相应的处理过程了,在这里, 我们并不将所有能够暴露的接口全部都暴露出去。 Adder接口, 被认为是一个与实现相关的细节,因此 ,我们并不暴露它。注意 ,它甚至并没有被包含到头文件中,仅仅 是 .cpp文件依赖 它 ( 通过 simple_adder.h 间接地依赖 ) 。 这个例子展示了, Fruit能够帮助 妳减少 大型项目中 include指令 的个数 (因而缩短 了编译时间 ) 。 如果不使用依赖注入,那么, 为了暴露出Incrementer 的实现, 我们需要包含 IncrementerImpl 的头文件, 而 IncrementerImpl实现代码 中又需要包含 SimpleAdder 的头文件。如果使用依赖注入 ,但不使用 Fruit ,那么, IncrementerImpl 的实现代码中不需要包含 SimpleAdder 的头文件,但是,客户代码中还是需要 同时 包含IncrementerImpl 和SimpleAdder 的头文件。
   啊!数字
   加1,实现完毕。
   
    
    
现在,实现部分
   也编写完毕,我们只需要编写
   
    main()
   
   函数了。
  
   
    #include "simple_incrementer.h"
   
   
    
    
   
   
    using fruit::Component;
   
   
    
   
   
    using fruit::Injector;
   
   
    
    
   
   
    int main() {
   
   
    
   
   
      Injector<Incrementer> injector(getSimpleIncrementerComponent());
   
   
    
   
   
      Incrementer* incrementer = injector.get<Incrementer*>();
   
   
    
   
   
    
   
   
    
   
   
      int x;
   
   
    
   
   
      std::cin >> x;
   
   
    
   
   
      std::cout << incrementer->increment(x) << std::endl;
   
   
    
   
   
    
   
   
    
   
   
      return 0;
   
   
    
   
   
    }
   
  
我们利用该组件构造了一个Injector,然后,通过该注入器获取了一个Incrementer 实例。这里,不需要包含任何的类定义头文件。
在以高昂的价格(或者开源, 这取决于妳的喜好 )发布了该程序之后, 我们收到了用户的一些反馈。部分用户 用得狠开心,但是 ,也有一部分用户注意到了一个问题, 对某个巨大的数字加1之后,会产生一个负数。 它们希望我 们加入一个 --checked 选项,用于启用溢出检 查。
我们的实现代码是模块化的(感谢依赖注入),因此,我们不需要对以上的任何组件进行修改。同时,Incrementer组件将具体的工作委托给了Adder,因此,我们此刻唯一要做的就是,对于Adder 写出一种会检查溢出情况的实现。
   
    // checked_adder.h
   
   
    
    
   
   
    #include "adder.h"
   
   
    
    
   
   
    fruit::Component<Adder> getCheckedAdderComponent();
   
  
   
    // checked_adder.cpp
   
   
    
    
   
   
    #include "checked_adder.h"
   
   
    
    
   
   
    class CheckedAdder : public Adder {
   
   
    
   
   
    private:
   
   
    
   
   
      bool add_overflows(int x, int y) {
   
  
... // 具体 的实现代码
   
    
   
   
    }
   
   
    
   
   
    
   
   
    
   
   
    public:
   
   
    
   
   
      INJECT(CheckedAdder()) = default;
   
   
    
   
   
    
   
   
    
   
   
      virtual int add(int x, int y) override {
   
   
    
   
   
        if (add_overflows(x, y)) {
   
   
    
   
   
          std::cerr << "CheckedAdder: detected overflow during addition of " << x << " and " << y << std::endl;
   
   
    
   
   
          abort();
   
   
    
   
   
        }
   
   
    
   
   
        return x + y;
   
   
    
   
   
      }
   
   
    
   
   
    };
   
   
    
    
   
   
    fruit::Component<Adder> getCheckedAdderComponent() {
   
   
    
   
   
      return fruit::createComponent()
   
   
    
   
   
        .bind<Adder, CheckedAdder>();
   
   
    
   
   
    }
   
  
并没有什么新鲜东西。现在,我们将这个新的组件与之前写好的IncrementComponent 组合起来。
   
    // checked_incrementer.h
   
   
    
    
   
   
    #include "incrementer.h"
   
   
    
    
   
   
    fruit::Component<Incrementer> getCheckedIncrementerComponent();
   
  
   
    // checked_incrementer.cpp
   
   
    
    
   
   
    #include "checked_incrementer.h"
   
   
    
    
   
   
    #include "incrementer_impl.h"
   
   
    
   
   
    #include "checked_adder.h"
   
   
    
    
   
   
    fruit::Component<Incrementer> getCheckedIncrementerComponent() {
   
   
    
   
   
      return fruit::createComponent()
   
   
    
   
   
        .install(getIncrementerImplComponent())
   
   
    
   
   
        .install(getCheckedAdderComponent());
   
   
    
   
   
    }
   
  
除了对 IncrementerComponent 的复用之外, 没有别的什么需要注意的东西了。
   
    // incrementer_component.h
   
   
    
    
   
   
    #include "incrementer.h"
   
   
    
    
   
   
    fruit::Component<Incrementer> getIncrementerComponent(bool checked);
   
  
   
    // incrementer_component.cpp
   
   
    
    
   
   
    #include "incrementer_component.h"
   
   
    
    
   
   
    #include "simple_incrementer.h"
   
   
    
   
   
    #include "checked_incrementer.h"
   
   
    
    
   
   
    fruit::Component<Incrementer> getIncrementerComponent(bool checked) {
   
   
    
   
   
      if (checked)
   
   
    
   
   
        return getCheckedIncrementerComponent();
   
   
    
   
   
      else
   
   
    
   
   
        return getSimpleIncrementerComponent();
   
   
    
   
   
    }
   
  
get * Component() 仅仅 是一个函数而已,因此, 我们可以让它提供出参数化的组件, 只需要 向这个函数加入参数,并且在函数中使用 if 判断 来引入 多个return语句。
现在,让我们重写main()函数,以接受新的参数,并且使用新的参数化的模块。
   
    // main.cpp
   
   
    
    
   
   
    #include "incrementer_component.h"
   
   
    
    
   
   
    using fruit::Component;
   
   
    
   
   
    using fruit::Injector;
   
   
    
    
   
   
    // Try
   
   
    一try:
   
   
    
   
   
    // echo 5 | ./incrementer
   
   
    
   
   
    // echo 2147483647 | ./incrementer
   
   
    
   
   
    // echo 2147483647 | ./incrementer --checked
   
   
    
   
   
    int main(int argc, const char* argv[]) {
   
   
    
   
   
    
   
   
    
   
   
      bool checked = false;
   
   
    
   
   
    
   
   
    
   
   
      if (argc == 2 && std::string(argv[1]) == "--checked")
   
   
    
   
   
        checked = true;
   
   
    
   
   
    
   
   
    
   
   
      Injector<Incrementer> injector(getIncrementerComponent(checked));
   
   
    
   
   
      Incrementer* incrementer(injector);
   
   
    
   
   
    
   
   
    
   
   
      int x;
   
   
    
   
   
      std::cin >> x;
   
   
    
   
   
      std::cout << incrementer->increment(x) << std::endl;
   
   
    
   
   
    
   
   
    
   
   
      return 0;
   
   
    
   
   
    }
   
  
此处 ,我们展示了另一种利用注入器来获取类实例的语法。 我们不是直接调用注入器的 get ,而是, 将注入器转换成我们想要的那种类型。 这是一种便利实现方法,用来避免 将类型重复两次 ( 与上面的 main函数对比 一下 ) 。
恒星
高圆圆
未知美人
Your opinionsHxLauncher: Launch Android applications by voice commands
